Skip to content

[libc++] Use Fuchsia futex operations - #133571

Merged
ldionne merged 7 commits into
llvm:mainfrom
frobtech:p/libcxx-fuchsia-futex
Apr 8, 2026
Merged

ldionne merged 7 commits into
llvm:mainfrom
frobtech:p/libcxx-fuchsia-futex

Conversation

@frobtech

@frobtech frobtech commented Mar 29, 2025 •

Copy link
Copy Markdown
Contributor

The basic futex operations have always been available on Fuchsia.
Wire them up to properly support C++20 atomic notify_*/wait.

@frobtech
frobtech requested a review from petrhosek March 29, 2025 07:59
@frobtech
frobtech marked this pull request as ready for review March 29, 2025 08:03
@frobtech
frobtech requested a review from a team as a code owner March 29, 2025 08:03
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 29, 2025
@llvmbot

llvmbot commented Mar 29, 2025

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-libcxx

Author: Roland McGrath (frobtech)

Changes

The basic futex operations have always been available on Fuchsia.
Wire them up to properly support C++20 atomic notify_*/wait.


Full diff: https://github.com/llvm/llvm-project/pull/133571.diff

3 Files Affected:

  • (modified) libcxx/include/__atomic/contention_t.h (+1-1)
  • (modified) libcxx/include/__cxx03/__atomic/contention_t.h (+1-1)
  • (modified) libcxx/src/atomic.cpp (+22)
diff --git a/libcxx/include/__atomic/contention_t.h b/libcxx/include/__atomic/contention_t.h
index 5b42a0125f875..cd3a8e4b29094 100644
--- a/libcxx/include/__atomic/contention_t.h
+++ b/libcxx/include/__atomic/contention_t.h
@@ -19,7 +19,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__))
+#if defined(__linux__) || defined(__Fuchsia__) || (defined(_AIX) && !defined(__64BIT__))
 using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
 #else
 using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
diff --git a/libcxx/include/__cxx03/__atomic/contention_t.h b/libcxx/include/__cxx03/__atomic/contention_t.h
index a97f0668da2fe..3fc3ccef78df5 100644
--- a/libcxx/include/__cxx03/__atomic/contention_t.h
+++ b/libcxx/include/__cxx03/__atomic/contention_t.h
@@ -19,7 +19,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__))
+#if defined(__linux__) || defined(__Fuchsia__) || (defined(_AIX) && !defined(__64BIT__))
 using __cxx_contention_t = int32_t;
 #else
 using __cxx_contention_t = int64_t;
diff --git a/libcxx/src/atomic.cpp b/libcxx/src/atomic.cpp
index c1af8d6f95aae..6de355b534b08 100644
--- a/libcxx/src/atomic.cpp
+++ b/libcxx/src/atomic.cpp
@@ -41,6 +41,10 @@
 // OpenBSD has no indirect syscalls
 #  define _LIBCPP_FUTEX(...) futex(__VA_ARGS__)
 
+#elif defined(__Fuchsia__)
+
+#  include <zircon/syscalls.h>
+
 #else // <- Add other operating systems here
 
 // Baseline needs no new headers
@@ -101,6 +105,24 @@ static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const vo
   _umtx_op(const_cast<__cxx_atomic_contention_t*>(__ptr), UMTX_OP_WAKE, __notify_one ? 1 : INT_MAX, nullptr, nullptr);
 }
 
+#elif defined(__Fuchsia__)
+
+static inline zx_futex_t const* __libcpp_zx_futex(__cxx_atomic_contention_t const volatile* ptr) {
+  // Implicitly link against the vDSO system call ABI without requiring the
+  // final link to specify -lzircon explicitly when statically linking libc++.
+#  pragma comment(lib, "zircon")
+  return const_cast<zx_futex_t const*>(reinterpret_cast<zx_futex_t const volatile*>(&ptr->__a_value));
+}
+
+static void
+__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) {
+  _zx_futex_wait(__libcpp_zx_futex(__ptr), __val, ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
+}
+
+static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr, bool __notify_one) {
+  _zx_futex_wake(__libcpp_zx_futex(__ptr), __notify_one ? 1 : UINT32_MAX);
+}
+
 #else // <- Add other operating systems here
 
 // Baseline is just a timed backoff

@huixie90 huixie90 self-assigned this Jun 28, 2025
Comment thread libcxx/include/__atomic/contention_t.h Resolved

@ldionne ldionne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM in principle but we will need to coordinate with #161086. I'll let @huixie90 chime in, please wait for his approval before merging. He'll decide whether he wants to land #161086 first and have this rebased, or the other way around.

Comment thread libcxx/src/atomic.cpp Resolved
@huixie90

Copy link
Copy Markdown
Member

This LGTM in principle but we will need to coordinate with #161086. I'll let @huixie90 chime in, please wait for his approval before merging. He'll decide whether he wants to land #161086 first and have this rebased, or the other way around.

@

This LGTM in principle but we will need to coordinate with #161086. I'll let @huixie90 chime in, please wait for his approval before merging. He'll decide whether he wants to land #161086 first and have this rebased, or the other way around.

@petrhosek let me know your plan. There will be some merge conflicts. My patch basically allow more types to going directly to the platform api under the unstable ABI

@frobtech
frobtech requested a review from philnik777 March 27, 2026 01:54
@frobtech
frobtech requested a review from huixie90 March 27, 2026 01:54
@frobtech

Copy link
Copy Markdown
Contributor Author

I've updated after all the internal refactorings of past months, and incorporated other review comments. I think it's looking pretty clean now.

Please take a fresh look!

Thanks.

@huixie90 huixie90 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some clarification

Comment thread libcxx/src/atomic.cpp
// final link to specify -lzircon explicitly when statically linking libc++.
# pragma comment(lib, "zircon")

return reinterpret_cast<zx_futex_t const*>(__ptr);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wanted to bring you attention of
libcxx/include/__atomic/atomic_waitable_traits.h

and here is the design intent of how things work.

atomic_waitable_traits.h defines a concept __has_native_atomic_wait that decides which types can directly call the platform futex wait, and which types needs to go through the global contention table proxy for platform wait.

And there are two ABI modes.

For the default ABI, __has_native_atomic_wait basically says only the __cxx_contention_t satisfies, which is int32_t in your case, can directly go to platform futex wait. I assume here zx_futex_t is exactly int32_t otherwise we might have UB

For another ABI which has _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE defined, which is controlled by the platform owner. in this case, i believe your platform does not enable it. but say, one day you decide to enable this ABI, the way it works is that. you can define __has_native_atomic_wait the way you want, the default concept in this mode is: any trivially copyable type with unique value representations, whose sizes matches __cxx_contention_t. in this case, __ptr and __val can be pointers to a wide range of types, e.g. a uint32_t, struct S { int32_t i;}; etc... In which case, I am not sure how reinterpret_cast<zx_futex_t const*> can be well defined. (anyway you don't need to worry about this if you don't plan to enable this ABI)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE enabled by dint of the fact that we always use ABI version 2. I'd be happy for it to be unconditionally enabled for Fuchsia, but I didn't see any precedent for that setting being controlled by anything but _LIBCPP_ABI_VERSION. In what sense is it controlled by the platform owner?

AFAICT there is no change to __atomic/atomic_waitable_traits.h required because __cxx_contention_t is already always int32_t (as my changes here to __atomic/contention_t.h) so the default case uses sizeof(__cxx_contention_t). For the same reason, the #ifdef __linux__ branch there seems superfluous.

I'm not sure what the concern is about the reinterpret_cast. zx_futex_t is just an integer type with the same size as int32_t, so it's layout compatible with any integer type or struct of integer type of that size.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what sense is it controlled by the platform owner?

Vendors can configure those individual ABI macros in the __config_site. See the doc here
https://libcxx.llvm.org/ABIGuarantees.html#abi-flags

And yes if you opt in _LIBCPP_ABI_VERSION to 2, you get all of these individual macros.

AFAICT there is no change to __atomic/atomic_waitable_traits.h required because __cxx_contention_t is already always int32_t

I think in your case, yes no action required. I mentioned that because some platforms can support multiple sizes for the platform wait. For example, Apple's ulock wait support both 4 bytes and 8 bytes wait.

I'm not sure what the concern is about the reinterpret_cast

I think it is kind of "it works in practice" but I think it is a language UB if you reinterpret_cast from memory location when there is actually no object of that type has started life time (implicitly or explicitly)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, so by "platform owner" you meant "person who sets the libc++ build parameters", not the owner of a particular platform's platform-specific code in libc++ sources. These are not always the same, and for Fuchsia it varies where I am both of those people and where I am only the latter. :-)

There is no language-based access here. The cast is just getting the pointer value to a system call, so regardless of the complexities of trivial object lifetime that might actually apply here, it's really outside the scope of those language rules anyway.

Thanks for the explanations! I think this change is good to go as is now. It just needs the approval from @philnik777 to be mergeable.

@ldionne
ldionne dismissed philnik777’s stale review April 8, 2026 21:37

Dismissing because the reviewer said it was fine to modify the 03 headers now -- so his original concern was resolved.

@ldionne
ldionne merged commit fbdfff4 into llvm:main Apr 8, 2026
79 checks passed
@frobtech
frobtech deleted the p/libcxx-fuchsia-futex branch April 8, 2026 22:02
YonahGoldberg pushed a commit to YonahGoldberg/llvm-project that referenced this pull request Apr 21, 2026
The basic futex operations have always been available on Fuchsia.
Wire them up to properly support C++20 atomic notify_*/wait.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants